package com.advaita.license;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public class License implements PathwayOptions

{
	private static String[] lookupCombination = { "999", "000", "001", "010",
			"011", "100", "101", "110", "111" };
	private static List<String> lookupCombinationList = Arrays
			.asList(lookupCombination);

	// ------------------------------------------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------------------------------------------

	protected static int lookupCombinationID(String groupOfThree) {
		int groupOfThreeID;

		groupOfThreeID = lookupCombinationList.indexOf(groupOfThree);
		return groupOfThreeID;
	}

	// ------------------------------------------------------------------------------------------------------------------

	protected static List<Selection> addToList(List<Selection> newList,
			String[] availableOptions) {
		for (String availableOptionIterator : availableOptions) {
			Selection clientSelection = new Selection();
			clientSelection.setSelection(availableOptionIterator);
			clientSelection.setIsEnabled(false);
			newList.add(clientSelection);
		}

		return newList;
	}

	// ------------------------------------------------------------------------------------------------------------------

	protected static List<Selection> consolidateCustomerSelectionsIntoOneList(
			Customer customer) {
		List<Selection> clientSelections = new ArrayList<Selection>();

		clientSelections.addAll(customer.licenseInfo.getOrganisms());
		clientSelections.addAll(customer.licenseInfo.getMicroArray());
		clientSelections.addAll(customer.licenseInfo.getGeneID());
		clientSelections.addAll(customer.licenseInfo.getDatabase());
		clientSelections.addAll(customer.licenseInfo.getAnalysis());

		for (int padBlanksCounter = 0; padBlanksCounter < (clientSelections
				.size() % 3); padBlanksCounter++) {
			addToList(clientSelections, BLANK);
		}

		return clientSelections;
	}

	// ------------------------------------------------------------------------------------------------------------------

	protected static String encodeCustomerSelections(
			List<Selection> clientSelections) {
		StringBuilder optionsSecretId = new StringBuilder();

		StringBuilder batchOfThree = new StringBuilder();
		String appendValue = "";

		for (int counter = 0; counter < clientSelections.size(); counter += 3) {
			for (int batchOfThreeCounter = 0; batchOfThreeCounter < 3; batchOfThreeCounter++) {
				appendValue = clientSelections.get(
						counter + batchOfThreeCounter).getIsEnabled() ? "1"
						: "0";
				batchOfThree.append(appendValue);
				appendValue = "";
			}
			optionsSecretId
					.append(lookupCombinationID(batchOfThree.toString()));
			batchOfThree.delete(0, batchOfThree.length());
		}
		;

		return optionsSecretId.toString();
	}

	// ------------------------------------------------------------------------------------------------------------------

	protected static String addMACAddress(Customer customer,
			String clientSuperSecretCode) {
		// Add MAC Address
		int macAddressLength = customer.licenseInfo.getMacAddress().length();

		for (int macAddressCounter = macAddressLength - 6; macAddressCounter < macAddressLength; macAddressCounter += 2) {
			int twoDigitsOfMacAddress = Integer.parseInt(
					customer.licenseInfo.getMacAddress().substring(macAddressCounter, macAddressCounter + 2), 16);
			String twoDigitString = String.format("%03d", twoDigitsOfMacAddress);
			clientSuperSecretCode += twoDigitString;
		}

		return clientSuperSecretCode;
	}

	// ------------------------------------------------------------------------------------------------------------------

	protected static String addExpirationDate(Customer customer,
			String clientSuperSecretCode) {
		DateFormat dateFormat = new SimpleDateFormat("MMddyyyy");
		clientSuperSecretCode += dateFormat.format(customer.licenseInfo
				.getExpDate());

		return clientSuperSecretCode;
	}

	// ------------------------------------------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------------------------------------------

	public static void generateSuperSecretcode(Customer customer) {
		List<Selection> clientSelections;
		String clientSuperSecretCode;

		clientSelections = consolidateCustomerSelectionsIntoOneList(customer);
		clientSuperSecretCode = License
				.encodeCustomerSelections(clientSelections);
		clientSuperSecretCode = addMACAddress(customer, clientSuperSecretCode);
		clientSuperSecretCode = addExpirationDate(customer,
				clientSuperSecretCode);

		customer.licenseInfo.setKey(clientSuperSecretCode);
	}

	// ------------------------------------------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------------------------------------------

	public static Customer decodeSuperSecretCode(String customerKey) {
		int customerSelectionsLength = 14;

		Customer decodedCustomer = new Customer();
		int combinationLookUpValue = 0;
		StringBuilder expandedCustomerSelections = new StringBuilder();
		String expandedCustomerSelectionsString;

		// Populates a Blank Customer with all Selections set to False.
		Customer.populateBlankCustomer(decodedCustomer);

		// Expand Customer Selections contained in first 14 digits of the Key to
		// 42 digits (Note 42nd digit is a Blank Selection that was added to
		// evenly mod by 3 )
		for (int customerKeyDigit = 0; customerKeyDigit < customerSelectionsLength; customerKeyDigit++) {
			combinationLookUpValue = Character.getNumericValue(customerKey
					.charAt(customerKeyDigit));
			expandedCustomerSelections
					.append(lookupCombination[combinationLookUpValue]);
			// System.out.println("Position in Key = " + customerKeyDigit +
			// " , and its value is " + combinationListLookUpValue +
			// " , and expandedCustomerSelections is " +
			// expandedCustomerSelections.toString() );
		}

		expandedCustomerSelectionsString = expandedCustomerSelections
				.toString();
		// System.out.println("    expandedCustomerSelectionsString.indexOf(8) :"
		// + Character.getNumericValue(expandedCustomerSelectionsString.charAt(
		// 8 )) );

		// Change the isEnabled value to True or False for only the options
		// selected in the String array: passedClientSelections
		int digitPointer = 0;

		for (Selection organismIterator : decodedCustomer.licenseInfo
				.getOrganisms()) {
			if (Character.getNumericValue(expandedCustomerSelectionsString
					.charAt(digitPointer)) == 1) {
				organismIterator.setIsEnabled(true);
				// System.out.println("just set " +
				// organismIterator.getSelection() + " to " +
				// organismIterator.getIsEnabled() );
			}
			;

			digitPointer++;
		}
		;

		for (Selection microArrayIterator : decodedCustomer.licenseInfo
				.getMicroArray()) {
			if (Character.getNumericValue(expandedCustomerSelectionsString
					.charAt(digitPointer)) == 1) {
				microArrayIterator.setIsEnabled(true);
				// System.out.println("just set " +
				// microArrayIterator.getSelection() + " to " +
				// microArrayIterator.getIsEnabled() );
			}
			;

			digitPointer++;
		}
		;

		for (Selection geneIDIterator : decodedCustomer.licenseInfo.getGeneID()) {
			if (Character.getNumericValue(expandedCustomerSelectionsString
					.charAt(digitPointer)) == 1) {
				geneIDIterator.setIsEnabled(true);
				// System.out.println("just set " +
				// geneIDIterator.getSelection() + " to " +
				// geneIDIterator.getIsEnabled() );
			}
			;

			digitPointer++;
		}
		;

		for (Selection pathwayDBIterator : decodedCustomer.licenseInfo
				.getDatabase()) {
			if (Character.getNumericValue(expandedCustomerSelectionsString
					.charAt(digitPointer)) == 1) {
				pathwayDBIterator.setIsEnabled(true);
				// System.out.println("just set " +
				// pathwayDBIterator.getSelection() + " to " +
				// pathwayDBIterator.getIsEnabled() );
			}
			;

			digitPointer++;
		}
		;

		for (Selection analysisIterator : decodedCustomer.licenseInfo
				.getAnalysis()) {
			if (Character.getNumericValue(expandedCustomerSelectionsString
					.charAt(digitPointer)) == 1) {
				analysisIterator.setIsEnabled(true);

				// System.out.println("just set " +
				// analysisIterator.getSelection() + " to " +
				// analysisIterator.getIsEnabled() );
			}
			;

			digitPointer++;
		}
		;

		// Decode MAC Address
		int customerMACAddressLength = 9;
		int encodedMacAddressLastDigit = customerSelectionsLength
				+ customerMACAddressLength;
		String threeEncodedDigitsOfMacAddress;
		String hexDecodedMacAddress;
		StringBuilder decodedMACAddress = new StringBuilder();

		for (int macAddressCounter = customerSelectionsLength; macAddressCounter < encodedMacAddressLastDigit; macAddressCounter += 3) {
			threeEncodedDigitsOfMacAddress = customerKey.substring(
					macAddressCounter, macAddressCounter + 3);
			hexDecodedMacAddress = Integer.toHexString(Integer
					.parseInt(threeEncodedDigitsOfMacAddress));
			decodedMACAddress.append(hexDecodedMacAddress);
		}

		decodedCustomer.licenseInfo.setMacAddress(decodedMACAddress.toString());

		// Decode Expiration Date
		int encodedExpirationDateFirstDigit = customerSelectionsLength
				+ customerMACAddressLength;
		int encodedExpirationDateLastDigit = encodedExpirationDateFirstDigit + 6;
		int date, month, year;
		String encodedDateSubString;
		Date decodedExpDate = new Date();

		encodedDateSubString = customerKey
				.substring(encodedExpirationDateFirstDigit,
						encodedExpirationDateLastDigit);

		month = Integer.parseInt(encodedDateSubString.substring(0, 2));
		date = Integer.parseInt(encodedDateSubString.substring(2, 4));
		year = 100 + Integer.parseInt(encodedDateSubString.substring(4, 6));

		decodedExpDate.setMonth(month - 1);
		decodedExpDate.setDate(date);
		decodedExpDate.setYear(year);

		decodedCustomer.licenseInfo.setExpDate(decodedExpDate);

		// Set the Customer Key that was Passed into this Method.
		decodedCustomer.licenseInfo.setKey(customerKey);

		return decodedCustomer;

	}
}
